import { hasOwn, isPlainObject } from "./util";

let strats = Object.create(null);

[
    "beforeCreate",
    "created",
    "beforeMount",
    "mounted",
    "beforeUpdate",
    "updated",
    "beforeDestroy",
    'destroyed'
].forEach(hook => {
    strats[hook] = mergeHook;
})
strats.data = function (parentVal, childVal, vm) {
    if (!vm) {
        if (typeof childVal !== 'function') {
            console.warn('data should be function !!');
        }
        if (!parentVal) {
            return childVal;
        } else {
            return mergeData(parentVal, childVal);
        }
    } else {
        if (!parentVal) {
            return childVal;
        } else {
            return mergeData(parentVal, childVal, vm);
        }
    }
}

// 合并components
strats.components = function (parentVal, childVal, vm) {
    const res = Object.create(parentVal);
    if (childVal) {
        for (let prop in childVal) {
            res[prop] = childVal[prop];
        }
    }
    return res;
}

function mergeData(parentVal, childVal, vm) {
    // 得到返回的对象
    parentVal = typeof parentVal === 'function' ? parentVal(this, this) : parentVal;
    childVal = typeof childVal === 'function' ? childVal.call(this, this) : childVal;
    for (let key in parentVal) {
        // 父亲属性在孩子没有
        if (!(key in childVal)) {
            childVal[key] = parentVal[key];
        } else { // 在孩子存在该属性
            if (isPlainObject(childVal[key]) && isPlainObject(parentVal[key])) {
                return mergeData(parentVal[key], childVal[key]);
            }
        }
    }
    return childVal;
}


function mergeHook(parentVal, childVal) {
    // 孩子存在，父亲存在:  使用父亲的去拼接孩子 
    // 孩子存在，父亲不存在:  用数组包裹孩子并返回
    // 孩子不存在: 直接返回父亲
    if (childVal) {
        if (parentVal) {
            return parentVal.concat(childVal);
        } else if (Array.isArray(childVal)) {
            return childVal;
        } else {
            return [childVal];
        }
    } else {
        return parentVal;
    }
}


export function mergeOptions(parentVal = {}, childVal = {}, vm) { // 可以通过vm判断时组件的data还是实例的data, 从而判断组件data需要函数
    function defaultMerge(parentVal, childVal) {
        return childVal ? childVal : parentVal;
    }
    let options = {};
    // 父亲身上有的
    for (let key in parentVal) {
        mergeField(key);
    }
    // 孩子有，父亲没有的。父亲身上有的属性已经和孩子合并完了
    for (let key in childVal) {
        if (!hasOwn(parentVal, key)) {
            mergeField(key);
        }
    }
    function mergeField(key) {
        const strat = strats[key] || defaultMerge;
        options[key] = strat(parentVal[key], childVal[key], vm);
    }
    return options;

}